/*
 * Copyright (c) 2023-2024 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.common.core.entity;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.elsfs.cloud.common.core.utils.TreeNode;

/** 构建树形结构 */
public abstract class TreeUtils {

  /**
   * 构建树形结构
   *
   * @param list 所有节点的集合
   * @param parentId 父节点id
   * @param <T> 节点类型
   * @param <ID> 节点id类型
   * @return 根节点集合
   */
  public static <T extends TreeNode<T, ID>, ID> List<T> buildTree(List<T> list, ID parentId) {
    List<T> root =
        list.stream()
            .filter(
                node -> node.getParentId() != null && Objects.equals(node.getParentId(), parentId))
            .sorted()
            .toList();
    var tempList = new ArrayList<>(list);
    // 减少遍历次数，删除根节点
    tempList.removeAll(root);
    // 构建 children
    root.forEach(node -> buildChild(tempList, node));
    if (root.isEmpty()) {
      return list;
    }
    return root;
  }

  /**
   * 为节点构建子节点
   *
   * @param list 所以的节点的集合
   * @param node 当前正在构建的节点
   * @param <T> 节点类型
   * @param <ID> 节点id类型
   */
  private static <T extends TreeNode<T, ID>, ID> void buildChild(List<T> list, T node) {
    List<T> children =
        list.stream()
            .filter(
                child -> child.getParentId() != null && child.getParentId().equals(node.getId()))
            .sorted()
            .toList();
    var tempList = new ArrayList<>(list);
    tempList.removeAll(children);
    children.forEach(
        child -> {
          buildChild(tempList, child);
          node.addChild(child);
        });
  }
}
